package com.dynamic.datasource.factory;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.datasource.AbstractDataSource;
import org.springframework.util.ReflectionUtils;

import javax.sql.DataSource;
import java.io.Closeable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * @author 王先堂
 * @Description 数据源包装
 * @createTime 2022/03/28/ 14:47:00
 */
@Slf4j
@Data
public class WrapDataSource extends AbstractDataSource implements Closeable {

    /**
     * 数据源名称
     */
    private String name;
    /**
     * 包装后的数据源
     */
    private DataSource wrapDataSource;
    /**
     * 目标数据源
     */
    private DataSource dataSource;

    /**
     * seata模式
     */
    private String seata;
    /**
     * spy
     */
    private Boolean p6spy;

    public WrapDataSource(String name, DataSource dataSource, DataSource wrapDataSource, String seata, Boolean p6spy) {
        this.dataSource = dataSource;
        this.wrapDataSource = wrapDataSource;
        this.name = name;
        this.seata = seata;
        this.p6spy = p6spy;
    }

    @Override
    public Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return dataSource.getConnection(username, password);
    }


    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return super.isWrapperFor(iface) || iface.isInstance(wrapDataSource) || iface.isInstance(dataSource);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T unwrap(Class<T> iface) {
        if (iface.isInstance(this)) {
            return (T) this;
        }
        if (iface.isInstance(wrapDataSource)) {
            return (T) wrapDataSource;
        }
        if (iface.isInstance(dataSource)) {
            return (T) dataSource;
        }
        return null;
    }

    @Override
    public void close() {
        Class<? extends DataSource> clazz = wrapDataSource.getClass();
        try {
            Method closeMethod = ReflectionUtils.findMethod(clazz, "close");
            if (closeMethod != null) {
                closeMethod.invoke(wrapDataSource);
            }
        } catch (IllegalAccessException | InvocationTargetException e) {
            log.warn("dynamic-datasource close the datasource named [{}] failed,", name, e);
        }
    }
}
